import mongoose, { Document, Schema, Model } from 'mongoose';

/**
 * 团队接口定义
 * 定义团队的基本属性和结构
 */
export interface ITeam {
  /** 团队名称 */
  name: string;
  /** 团队描述 */
  description?: string;
  /** 团队负责人ID */
  leaderId?: mongoose.Types.ObjectId;
  /** 状态：1-正常，0-禁用 */
  status: number;
  /** 创建时间 */
  createdAt: Date;
  /** 更新时间 */
  updatedAt: Date;
}

/**
 * 团队文档接口
 * 继承ITeam接口和mongoose的Document接口
 */
export interface ITeamDocument extends ITeam, Document {
  /** 转换为JSON格式，用于API响应 */
  toJSON(): any;
}

/**
 * 团队模型接口
 * 定义团队模型的静态方法
 */
export interface ITeamModel extends Model<ITeamDocument> {
  /**
   * 根据团队名称查找团队
   * @param name 团队名称
   * @returns 团队文档或null
   */
  findByName(name: string): Promise<ITeamDocument | null>;
  
  /**
   * 根据负责人ID查找团队
   * @param leaderId 负责人ID
   * @returns 团队文档数组
   */
  findByLeader(leaderId: mongoose.Types.ObjectId): Promise<ITeamDocument[]>;
  
  /**
   * 根据状态查找团队
   * @param status 状态值
   * @returns 团队文档数组
   */
  findByStatus(status: number): Promise<ITeamDocument[]>;
}

/**
 * 团队数据模型Schema定义
 * 定义团队在MongoDB中的数据结构
 */
const TeamSchema = new Schema<ITeamDocument>({
  // 团队名称，必填，唯一
  name: {
    type: String,
    required: [true, '团队名称不能为空'],
    unique: true,
    trim: true,
    maxlength: [100, '团队名称不能超过100个字符']
  },
  
  // 团队描述，可选，最大长度500
  description: {
    type: String,
    trim: true,
    maxlength: [500, '团队描述不能超过500个字符']
  },
  
  // 团队负责人ID，可选，引用用户表
  leaderId: {
    type: Schema.Types.ObjectId,
    ref: 'User'
  },
  
  // 状态：1-正常，0-禁用，默认为1
  status: {
    type: Number,
    required: true,
    enum: [0, 1],
    default: 1,
    index: true
  }
}, {
  // 自动添加创建时间和更新时间
  timestamps: true,
  // 设置集合名称
  collection: 'teams'
});

/**
 * 团队名称唯一性索引
 * 确保团队名称在数据库中唯一
 */
TeamSchema.index({ name: 1 }, { unique: true });

/**
 * 复合索引：状态和创建时间
 * 用于按状态和时间排序查询
 */
TeamSchema.index({ status: 1, createdAt: -1 });

/**
 * 负责人索引
 * 用于快速查找某个负责人管理的团队
 */
TeamSchema.index({ leaderId: 1 });

/**
 * 保存前中间件
 * 在保存团队数据前进行数据验证和处理
 */
TeamSchema.pre('save', function(next) {
  // 如果是新文档或名称被修改，进行名称格式验证
  if (this.isNew || this.isModified('name')) {
    // 团队名称不能包含特殊字符
    const nameRegex = /^[\u4e00-\u9fa5a-zA-Z0-9\s\-_]+$/;
    if (!nameRegex.test(this.name)) {
      return next(new Error('团队名称只能包含中文、英文、数字、空格、横线和下划线'));
    }
  }
  
  next();
});

/**
 * 更新前中间件
 * 在更新团队数据前进行数据验证
 */
TeamSchema.pre(['updateOne', 'findOneAndUpdate'], function(next) {
  const update = this.getUpdate() as any;
  
  // 如果更新名称，进行格式验证
  if (update.name || (update.$set && update.$set.name)) {
    const name = update.name || update.$set.name;
    const nameRegex = /^[\u4e00-\u9fa5a-zA-Z0-9\s\-_]+$/;
    if (!nameRegex.test(name)) {
      return next(new Error('团队名称只能包含中文、英文、数字、空格、横线和下划线'));
    }
  }
  
  next();
});

/**
 * 实例方法：转换为JSON格式
 * 用于API响应时隐藏敏感信息
 */
TeamSchema.methods.toJSON = function() {
  const obj = this.toObject();
  
  // 返回团队信息，包含所有字段
  return {
    _id: obj._id,
    name: obj.name,
    description: obj.description,
    leaderId: obj.leaderId,
    status: obj.status,
    createdAt: obj.createdAt,
    updatedAt: obj.updatedAt
  };
};

/**
 * 静态方法：根据团队名称查找团队
 * @param name 团队名称
 * @returns 团队文档或null
 */
TeamSchema.statics.findByName = function(name: string): Promise<ITeamDocument | null> {
  const trimmedName = name.trim();
  // 使用精确匹配，确保大小写敏感
  return this.findOne({ name: trimmedName }).collation({ locale: 'en', strength: 3 }).exec();
};

/**
 * 静态方法：根据负责人ID查找团队
 * @param leaderId 负责人ID
 * @returns 团队文档数组
 */
TeamSchema.statics.findByLeader = function(leaderId: mongoose.Types.ObjectId): Promise<ITeamDocument[]> {
  return this.find({ leaderId }).sort({ createdAt: -1 }).exec();
};

/**
 * 静态方法：根据状态查找团队
 * @param status 状态值
 * @returns 团队文档数组
 */
TeamSchema.statics.findByStatus = function(status: number): Promise<ITeamDocument[]> {
  return this.find({ status }).sort({ createdAt: -1 }).exec();
};

/**
 * 创建并导出团队模型
 * 使用TeamSchema创建Team模型
 */
export const Team = mongoose.model<ITeamDocument, ITeamModel>('Team', TeamSchema);

// 默认导出Team模型
export default Team;